/**
 * @author Paulo Faria Reis
 * @created 15 Mar 2012
 *
 */
package networkoperations;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import controller.DataStore;
import controller.FileData;

/**
 * @author Paulo Faria Reis
 */
public class FileSender extends Thread {

   String fileHash;	// ID (hash) of file to send.  
   DataStore dataStorage;
   boolean dontStop = true;

   /**
    * @param dataStorage 
    * 
    */
   public FileSender(DataStore dataStor) {
	dataStorage = dataStor;
   }

   /* (non-Javadoc)
    * @see java.lang.Thread#run()
    */
   @Override
   public void run() {
	try {
	   MulticastSocket dataSocket = new MulticastSocket();
	   dataSocket.setTimeToLive(1);
	   byte[] msgOut = new byte[1536];
	   DatagramPacket chunkPacket = new DatagramPacket(msgOut, msgOut.length, dataStorage.getMcAddress(), dataStorage.getDataPort());
	   
	   while(dataStorage.keepWorking() && dontStop) {
		if(dataStorage.existsWork()) {
		   FileData aFile = dataStorage.giveMeWork();
		   long chunkIdToSend = aFile.giveMeAChunk();
		   byte[] bytesToSend = null;
		   RandomAccessFile raf = new RandomAccessFile(aFile.getFilename(), "r");
		   raf.read(bytesToSend, (int)(chunkIdToSend * 1024), 1024);
		   chunkPacket.setData(swap(aFile.getHash().getBytes()), 0, 256);
		   chunkPacket.setData(longToLittleEndian(chunkIdToSend), 256, 64);
		   chunkPacket.setData(swap(bytesToSend), 512, 1024);
		   dataSocket.send(chunkPacket);
		   dataStorage.chunkSent(aFile.getHash(), chunkIdToSend);
		   raf.close();
		}
		else {
		   sleep(1000);	// No chunks to send, wait for a sec.
		}
	   }
	}
	catch (IOException e) {
	   System.out.println("IO related error.");
	}
	catch (InterruptedException e) {
	   System.out.println("Something waked me.");
	}
   }

   /**
    * Converts a long to a byte array in little endian order.
    * @param number
    * @return
    */
   byte[] longToLittleEndian(long number) {
	ByteBuffer bb = ByteBuffer.allocate(8);
	bb.order(ByteOrder.LITTLE_ENDIAN);
	bb.putLong(number);
	return bb.array();
   }

   /**
    * Change the endianness of a array of bytes.
    * @param src
    * @return
    */
   byte[] swap(byte[] src) {
	ByteBuffer bb = ByteBuffer.allocate(1024);
	bb.order(ByteOrder.LITTLE_ENDIAN);
	bb.put(src);
	return bb.array();
   }
   
      
   public void myStop() {
	dontStop = false;
   }
}
